#ifndef BASE_DARR_HPP
#define BASE_DARR_HPP

/**
 * \brief base dynamic array class
 * \note
 * \tparam T the object type
 * \retval None
 */
template <class T>
class base_darr {
public:
  using value_type = T;
  using reference_type = T &;
  using pointer_type = T *;
  using const_reference_type = const T &;
  using const_pointer_type = const T *;
  using size_type = unsigned long long;

protected:
  static const size_type MAX_CACHE_CAPACITY = 32; // max stack memory
  size_type _capacity; // exact capacity in this array
  size_type _size;     // exact size in this array element

  ~base_darr();

  value_type _cache_mem_[MAX_CACHE_CAPACITY]; // cache memory in this array
  const_pointer_type _head_mem_head;          // heap memory pointer

protected:
  static bool allocate_arr( base_darr &ref, size_type size );
  static void release_arr( base_darr &ref, size_type size );

public:
  base_darr();

  size_type size() const { return _size; }
  bool empty() const { return _size == 0; }

  virtual void reset(); // clear all data in this array

private:
  /**
   * \brief the base array allocator is singleton
   * \note
   * \retval None
   */
  class base_darr_allocator {
  public:
    static base_darr_allocator &_get_allocator() {
      // global state
      static base_darr_allocator _instance;
      return _instance;
    }

    const_pointer_type _allocate( size_type capacity );
    void _deallocate( const_pointer_type head, size_type capacity );

    const size_type DEFAULT_CAPACITY = 32; // Default capacity in this array
  private:
    // TODO: save every instanced child memory header used in reallocate
    base_darr *_instance_darr;
    pointer_type _heap_mem;   // heap memory head
    size_type _base_size;     // has been used memory size
    size_type _base_capacity; // current heap memory size
  private:
    base_darr_allocator();
    ~base_darr_allocator();

    void _base_expand( size_type capacity ); // expand current heap capacity
  };
};

#endif